Secciones

Referencias

International aid may take the form of multilateral aid – provided through international bodies such as the UN, or NGOs such as Oxfam – or bilateral aid, which operates on a government-to-government basis. There is considerable debate about whether international aid works, in the sense of reducing poverty and stimulating development.

However, the effectiveness of aid is often diluted by corruption. Aid is invariably channeled through the governments of recipient countries, in which power is often concentrated in the hands of a few politicians and bureaucrats, and the mechanisms of accountability are, at best, poorly developed. This tends to benefit corrupt leaders and elites rather than the people, projects and programs for which it was intended.

Watts, Carl. (2014). Re: Does foreign aid help the developing countries towards development?. Retrieved from: https://www.researchgate.net/post/Does_foreign_aid_help_the_developing_countries_towards_development/5322005ed039b1e7648b459c/citation/download.

The hypothesis that foreign aid can promote growth in developing countries was explored, using panel data series for foreign aid, while accounting for regional differences in Asian, African, Latin American, and the Caribbean countries as well as the differences in income levels, the results of this study also indicate that foreign aid has mixed effects on economic growth in developing countries.

Ekanayake, E. & Chatrna, Dasha. (2010). The effect of foreign aid on economic growth in developing countries. Journal of International Business and Cultural Studies. 3.

This study examines the relationships between foreign aid, institutional structure, and economic performance for 80 countries in Europe, America, Africa, and Asia. It is found that official development assistance and the quality of institutional structure in the sample countries affect economic growth positively.

Hayaloğlu, Pınar. (2023). Foreign Aid, Institutions, and Economic Performance in Developing Countries. Eskişehir Osmangazi Üniversitesi İktisadi ve İdari Bilimler Dergisi. 18. 748-765. 10.17153/oguiibf.1277348.

Manual para replicar

Cargando Librerias

Algunas librerias y paquetes usados para obtener y descargar los datos

library(tidyverse) # manejo de dataframes
library(reshape2)  # para tranfromar data de long a wide
library(WDI)       # libreria para acceder a metadata de banco mundial
library(readxl)    # leer archivos de excel
library(readr)     # leer archivos csv
library(visdat)    # visualizacion de datos como graficos
library(plotly)    # graficos
library(purrr)     # funcion map
library(plm)       # modelos lineales para datos panel
library(car)       # test y utilidades para modelos
library(htmltools) # para imprimir graficos en html
library(urca)      # Unit root test
library(tseries)   # Dickey Fuller test (serie estacionaria)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 

    ‘tseries’ version: 0.10-57

    ‘tseries’ is a package for time series analysis and computational finance.

    See ‘library(help="tseries")’ for details.
library(lmtest)    # Pruebas de modelos lineales

Obtener datos

Datos para paises bajos ingresos sean utilizados, segun clasificación del banco mundial, hay 26 paises de bajos ingresos y 51 de ingresos medios bajos

country_class <- read_excel("CLASS.xlsx")

country_class %>%
  filter(!is.na(Region), !is.na(`Income group`)) %>%
  group_by(`Income group`) %>%
  summarise(countries = n()) %>%
  arrange(factor(`Income group`, levels = c('High income', 'Upper middle income', 'Lower middle income', 'Low income')))

Listado de paises a analisar:

my_countries <- country_class %>%
  filter(!is.na(Region), `Income group` %in% c('Low income', 'Lower middle income')) %>%
  select(Code)
my_countries %>% merge(country_class) %>% select(Code, Economy)

Hacer la respectiva asociacion de nombres iso3c e iso2c

my_countries$iso2c <- WDI_data$country %>%
  filter(iso3c %in% my_countries$Code) %>%
  .$iso2c

Datos del banco mundial (para ODA y los indices de gobernanza) y el Human Development Reports API son descargados desde scripts de Python. Son almacenados en archivos CSV y luego son cargados aqui:

cargar HDI

datos_HDI <- read_csv("datos_python_HDI.csv", col_names = c('Code', 'iso2c', 'indicator', 'year', 'value'), 
                      col_types = list(col_character(), col_character(), col_character(), col_double(), col_double()))

hdi_indicators <- c('hdi') #datos_HDI %>% distinct(indicator) %>% .$indicator
datos_HDI <- datos_HDI %>% filter(indicator %in% hdi_indicators)

cargar ODA, GDP, POP.GROW

oda_indicators <- c(
'DT_ODA_ALLD_CD',
#'DT_ODA_ALLD_KD',
#'DT_ODA_OATL_CD',
#'DT_ODA_OATL_KD',
#'DT_ODA_ODAT_CD',
#'DT_ODA_ODAT_GI_ZS',
#'DT_ODA_ODAT_GN_ZS',
#'DT_ODA_ODAT_KD',
#'DT_ODA_ODAT_MP_ZS',
'DT_ODA_ODAT_PC_ZS'#,
#'DT_ODA_ODAT_XP_ZS'
)
gob_indicators <- c(
'CC_EST',
#'CC_NO_SRC',
#'CC_PER_RNK',
#'CC_PER_RNK_LOWER',
#'CC_PER_RNK_UPPER',
#'CC_STD_ERR',
'GE_EST',
#'GE_NO_SRC',
#'GE_PER_RNK',
#'GE_PER_RNK_LOWER',
#'GE_PER_RNK_UPPER',
#'GE_STD_ERR',
'PV_EST',
# 'PV_NO_SRC',
# 'PV_PER_RNK',
# 'PV_PER_RNK_LOWER',
# 'PV_PER_RNK_UPPER',
# 'PV_STD_ERR',
'RQ_EST',
# 'RQ_NO_SRC',
# 'RQ_PER_RNK',
# 'RQ_PER_RNK_LOWER',
# 'RQ_PER_RNK_UPPER',
# 'RQ_STD_ERR',
'RL_EST',
# 'RL_NO_SRC',
# 'RL_PER_RNK',
# 'RL_PER_RNK_LOWER',
# 'RL_PER_RNK_UPPER',
# 'RL_STD_ERR',
'VA_EST'#,
# 'VA_NO_SRC',
# 'VA_PER_RNK',
# 'VA_PER_RNK_LOWER',
# 'VA_PER_RNK_UPPER',
# 'VA_STD_ERR'
)
gdp_indicators <- c(
# 'NY_ADJ_NNTY_PC_CD',
# 'NY_ADJ_NNTY_PC_KD',
# 'NY_ADJ_NNTY_PC_KD_ZG',
# 'NY_GDP_PCAP_CN',
# 'NY_GDP_PCAP_KN',
'NY_GDP_PCAP_CD',
# 'NY_GDP_PCAP_KD',
# 'NY_GDP_MKTP_KD_ZG',
# 'NY_GDP_DEFL_ZS_AD',
# 'NY_GDP_DEFL_ZS',
# 'NY_GDP_MKTP_CD',
# 'NY_GDP_MKTP_CN',
# 'NY_GDP_MKTP_KN',
# 'NY_GDP_MKTP_KD',
# 'NY_GDP_PCAP_KD_ZG',
# 'NY_GDP_PCAP_PP_KD',
# 'NY_GDP_PCAP_PP_CD',
# 'SL_GDP_PCAP_EM_KD',
'SP_POP_GROW'
)

datos_WB <- data.frame(indicator = character(), iso2c = character(), year = double(), value = double())

suppressWarnings(
  for (indicator in c(oda_indicators, gob_indicators, gdp_indicators)) {
    datos_WB <- rbind(datos_WB, read_csv(paste("datos_python", indicator, ".csv", sep =''), 
                                           col_names = c('indicator', 'iso2c', 'year', 'value'),
                                           col_types = list(col_character(), col_character(), col_double(), col_double())))
  }
)

cargar POVERTY

Poverty <- read_excel("GlobalExtremePovertyDollaraDay_Compact.xlsx", sheet = "Data Long Format")

names(Poverty) <- c("ccode", "country", "year", "value")

Poverty[Poverty=="Cape Verde"] <- "Cabo Verde"
Poverty[Poverty=="Congo"] <- "Congo, Rep."
Poverty[Poverty=="Egypt"] <- "Egypt, Arab Rep."
Poverty[Poverty=="Iran"] <- "Iran, Islamic Rep."
Poverty[Poverty=="Kyrgyzstan"] <- "Kyrgyz Republic"
Poverty[Poverty=="Laos"] <- "Lao PDR"
Poverty[Poverty=="Macedonia"] <- "North Macedonia"
Poverty[Poverty=="Russia"] <- "Russian Federation"
Poverty[Poverty=="Slovakia"] <- "Slovak Republic"
Poverty[Poverty=="South Korea"] <- "Korea, Rep."
Poverty[Poverty=="Swaziland"] <- "Eswatini"
Poverty[Poverty=="Syria"] <- "Syrian Arab Republic"
Poverty[Poverty=="The Gambia"] <- "Gambia, The"
Poverty[Poverty=="Turkey"] <- "Turkiye"
Poverty[Poverty=="Venezuela"] <- "Venezuela, RB"
Poverty[Poverty=="Yemen"] <- "Yemen, Rep."

Poverty <- Poverty %>%
  filter(year > 1994) %>%
  merge(WDI_data$country, all.x = TRUE) %>%
  mutate(indicator = 'POV') %>%
  merge(my_countries) %>%
  select(indicator, iso2c, year, value)

cargar Political Civil Liberties

PC_LIB <- read_csv("political-civil-liberties-index.csv")
Rows: 33643 Columns: 4── Column specification ──────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): Entity, Code
dbl (2): year, value
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
PC_LIB <- PC_LIB %>%
  filter(year > 1994, !is.na(Code)) %>%
  merge(my_countries) %>%
  mutate(indicator = 'POL.CIV.LIB') %>%
  select(indicator, iso2c, year, value)

Manipulacion de Datos

Transformar datos a la estructura wide

datos_paper <- rbind(datos_WB, datos_HDI %>% select(indicator, iso2c, year, value), Poverty, PC_LIB) %>%
  pivot_wider(names_from = indicator, values_from = value)

Promedio de Indices de Gobernanza

datos_paper <- datos_paper %>% mutate(GOV =  (CC.EST + GE.EST + PV.EST + RQ.EST + RL.EST + VA.EST) / 6)

Operador Diferencia

datos_paper <- datos_paper %>% arrange(iso2c, year) %>% 
        mutate(hdi_diff = case_when(iso2c == dplyr::lag(iso2c) ~ hdi - dplyr::lag(hdi), TRUE ~ NA_real_), 
               NY.GDP.PCAP.CD_diff = case_when(iso2c == dplyr::lag(iso2c) ~ NY.GDP.PCAP.CD - dplyr::lag(NY.GDP.PCAP.CD), TRUE ~ NA_real_),
               DT.ODA.ALLD.CD_diff = case_when(iso2c == dplyr::lag(iso2c) ~ DT.ODA.ALLD.CD - dplyr::lag(DT.ODA.ALLD.CD), TRUE ~ NA_real_),
               DT.ODA.ODAT.PC.ZS_diff = case_when(iso2c == dplyr::lag(iso2c) ~ DT.ODA.ODAT.PC.ZS - dplyr::lag(DT.ODA.ODAT.PC.ZS), TRUE ~ NA_real_),
               GOV_diff = case_when(iso2c == dplyr::lag(iso2c) ~ GOV - dplyr::lag(GOV), TRUE ~ NA_real_),
               POV_diff = case_when(iso2c == dplyr::lag(iso2c) ~ POV - dplyr::lag(POV), TRUE ~ NA_real_))

Clasificaciones dicotomicas

datos_paper <- datos_paper %>% mutate(GOV_GOOD = case_when(GOV >= 0 ~ 1, TRUE ~ 0))
plot_ly(data = datos_paper %>% filter(!is.na(GOV)), y = ~ GOV, type = 'scatter', mode = 'markers') %>%
  layout(title = 'Indice promedio de gobernanza', xaxis = list(title = 'Registros'))

datos_paper <- datos_paper %>% mutate(POL.CIV.LIB_GOOD = case_when(POL.CIV.LIB >= 0.5 ~ 1, TRUE ~ 0))
plot_ly(data = datos_paper %>% filter(!is.na(POL.CIV.LIB)), y = ~ POL.CIV.LIB, type = 'scatter', mode = 'markers') %>%
  layout(title = 'Indice libertades politicas y civiles', xaxis = list(title = 'Registros'))

Variables logaritmo

datos_paper <- datos_paper %>% mutate(DT.ODA.ALLD.CD_LOG = log(DT.ODA.ALLD.CD))
Aviso: There was 1 warning in `mutate()`.
ℹ In argument: `DT.ODA.ALLD.CD_LOG = log(DT.ODA.ALLD.CD)`.
Caused by warning in `log()`:
! NaNs produced

Variables cuadradas

datos_paper <- datos_paper %>% mutate(DT.ODA.ODAT.PC.ZS_2 = DT.ODA.ODAT.PC.ZS ^ 2,
                                      DT.ODA.ALLD.CD_2 = DT.ODA.ALLD.CD ^ 2,
                                      DT.ODA.ALLD.CD_LOG_2 = DT.ODA.ALLD.CD_LOG ^ 2,)

Colocar nombres a variables

names(datos_paper) <- c('country','year','ODA.ALL','ODA.PC','CC.EST','GE.EST','PV.EST','RQ.EST','RL.EST','VA.EST','GDP.PC','GROW','hdi','POV','POL.CIV.LIB','GOV','hdi_diff','GDP.PC_diff','ODA.ALL_diff','ODA.PC_diff','GOV_diff','POV_diff','GOV_GOOD','POL.CIV.LIB_GOOD','ODA.ALL_LOG','ODA.PC_2','ODA.ALL_2','ODA.ALL_LOG_2')

Visualizacion de Datos

ODA
vis_dat(datos_paper %>% select(ODA.ALL, ODA.PC)) 

  # DT.ODA.OATL.CD and DT.ODA.OATL.KD faltan
  # DT.ODA.ODAT.GI.ZS, DT.ODA.ODAT.GN.ZS, DT.ODA.ODAT.MP.ZS and DT.ODA.ODAT.XP.ZS tienen faltas
  # Un par de ocurrencias pais-año que faltan datos
GDP
vis_dat(datos_paper %>% select(GDP.PC)) 

  # NY.GDP.PCAP.CN, GDP.PC, NY.GDP.MKTP.CD, NY.GDP.MKTP.CN son buenos candidatos para usar como variables, 
  # 'SY'falta PIB per Capita en 2022, 2023 sin datos algunos paises
GOV
vis_dat(datos_paper %>% arrange(year) %>% select(all_of(gsub("_", ".", gob_indicators)))) 

  # Datos del 2000 para atras tienen espacios faltantes 
HDI
vis_dat(datos_paper %>% arrange(year) %>% select(all_of(hdi_indicators))) 

  # abr, co2_prod, le, le_f, le_m, mmr son las pocas categorias sin datos faltantes
  # hdi faltante en multiples ocaciones
POP.GROW
vis_dat(datos_paper %>% arrange(country) %>% select(GROW))

POV
vis_dat(datos_paper %>% arrange(year, country) %>% select(POV))


# 'AF', 'CD', 'CI', 'DJ', 'KH', 'LR', 'MR', 'PG', 'ST', 'TJ', 'UZ', 'VN', 'WS' no tienen datos de esta variable
# Porcentaje de personas por debajo de la linea de extrema pobreza (Dollar a day)
POLITICAL CIVIL LIBERTY
vis_dat(datos_paper %>% arrange(country) %>% select(POL.CIV.LIB)) 

  # KI  MR  SD  WS  son paises sin datos para estos años

Tablas informativas

temp <- datos_paper %>% 
   filter(!year <  2002, !year > 2022, !country %in% c('SS')) %>%
   merge(my_countries, by.x = "country", by.y = "iso2c") %>%
   merge(country_class) %>%
   group_by(`Income group`) %>%
   summarise('2002 - 2022' = sum(ODA.ALL))

temp

plot_ly(temp %>% 
          mutate(`Income group` = case_when(`Income group` == 'Low income' ~ 'Ingresos Bajos',
                                            `Income group` == 'Lower middle income' ~ 'Ingresos Medios-bajos')),
        labels = ~`Income group`, values = ~`2002 - 2022`, type = 'pie', textinfo = 'label+percent') %>%
  layout(title = 'Asistencia Oficial para el Desarrollo recibida total 2002 - 2022',
         plot_bgcolor = "#e5ecf6")

########################################################################

temp <- datos_paper %>% 
  mutate(y_range = case_when(year < 2007 ~ '2002 - 2006',
                             year < 2012 ~ '2007 - 2011',
                             year < 2017 ~ '2012 - 2016',
                             TRUE ~ '2017 - 2022')) %>%
  filter(!year <  2002, !year > 2022, !country %in% c('SS')) %>%
  merge(my_countries, by.x = "country", by.y = "iso2c") %>%
  merge(country_class) %>%
  group_by(`Income group`, y_range) %>%
  summarise(sum=sum(ODA.ALL), .groups = "drop")

temp %>% pivot_wider(names_from = y_range, values_from = sum)

plot_ly(temp %>% pivot_wider(names_from = `Income group`, values_from = sum), 
        x = ~y_range, y = ~`Lower middle income`, name = 'Ingresos Medios-bajos', type = 'bar') %>% 
  add_trace(y = ~`Low income`, name = 'Ingresos Bajos') %>% 
  layout(title = 'Asistencia Oficial para el Desarrollo recibida total',
         yaxis = list(title = 'Dolares Actuales'), xaxis = list(title = 'Periodo'), barmode = 'group')

########################################################################

temp <- datos_paper %>% 
  filter(!year <  2002, !year > 2022, !country %in% c('SS')) %>%
  merge(my_countries, by.x = "country", by.y = "iso2c") %>%
  merge(country_class) %>%
  group_by(Region) %>%
  summarise('2002 - 2022' = sum(ODA.ALL))

temp

plot_ly(temp, labels = ~Region, values = ~`2002 - 2022`, type = 'pie', textinfo = 'label+percent') %>%
  layout(title = 'Asistencia Oficial para el Desarrollo recibida total 2002 - 2022',
         plot_bgcolor = "#e5ecf6")

########################################################################

temp <- datos_paper %>% 
  mutate(y_range = case_when(year < 2007 ~ '2002 - 2006',
                             year < 2012 ~ '2007 - 2011',
                             year < 2017 ~ '2012 - 2016',
                             TRUE ~ '2017 - 2022')) %>%
  filter(!year <  2002, !year > 2022, !country %in% c('SS')) %>%
  merge(my_countries, by.x = "country", by.y = "iso2c") %>%
  merge(country_class) %>%
  group_by(Region, y_range) %>%
  summarise(sum=sum(ODA.ALL), .groups = "drop") 

temp %>%
  pivot_wider(names_from = y_range, values_from = sum)

plot_ly(temp %>% pivot_wider(names_from = Region, values_from = sum), 
        x = ~y_range, y = ~`Sub-Saharan Africa`, name = 'Sub-Saharan Africa', type = 'bar') %>% 
  add_trace(y = ~`East Asia & Pacific`, name = 'East Asia & Pacific') %>% 
  add_trace(y = ~`Middle East & North Africa`, name = 'Middle East & North Africa') %>% 
  add_trace(y = ~`South Asia`, name = 'South Asia') %>% 
  add_trace(y = ~`Latin America & Caribbean`, name = 'Latin America & Caribbean') %>% 
  add_trace(y = ~`Europe & Central Asia`, name = 'Europe & Central Asia') %>% 
  layout(title = 'Asistencia Oficial para el Desarrollo recibida total',
         yaxis = list(title = 'Dolares Actuales'), xaxis = list(title = 'Periodo'), barmode = 'group')

########################################################################

temp <- datos_paper %>% 
  filter(!year <  2002, !year > 2022, !country %in% c('SS', 'KP')) %>%
  merge(my_countries, by.x = "country", by.y = "iso2c") %>%
  merge(country_class)

suppressWarnings(
  plot_ly(temp %>% filter(year %in% c(2002, 2012, 2022)), x = ~year, y = ~hdi, color = ~`Income group`, type = "box") %>%
    layout(title = 'Indice de desarrollo Humano en paises de Ingresos Bajos e Ingresos Medios-bajos', 
           boxmode = "group")
)
Aviso: Ignoring 9 observationsAviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
Aviso: Ignoring 9 observationsAviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
suppressWarnings(
  plot_ly(temp %>% filter(year %in% c(2002, 2012, 2022)), x = ~year, y = ~hdi, color = ~Region, type = "box") %>%
    layout(title = 'Indice de desarrollo Humano segun Region', boxmode = "group")
)
Aviso: Ignoring 9 observationsAviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
Aviso: Ignoring 9 observationsAviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
########################################################################

suppressWarnings(
  plot_ly(temp %>% filter(year %in% c(2002, 2012, 2022)), x = ~year, y = ~GOV, color = ~`Income group`, type = "box") %>%
    layout(title = 'Indice de gobernanza en paises de Ingresos Bajos e Ingresos Medios-bajos', boxmode = "group")
)
Aviso: Ignoring 4 observationsAviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
Aviso: Ignoring 4 observationsAviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
suppressWarnings(
  plot_ly(temp %>% filter(year %in% c(2002, 2012, 2022)), x = ~year, y = ~GOV, color = ~Region, type = "box") %>%
    layout(title = 'Indice de gobernanza segun Region', boxmode = "group")
)
Aviso: Ignoring 4 observationsAviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
Aviso: Ignoring 4 observationsAviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
########################################################################

suppressWarnings(
  plot_ly(temp %>% filter(year %in% c(2002, 2012, 2022)), x = ~year, y = ~GDP.PC, color = ~`Income group`, type = "box") %>%
    layout(title = 'PIB per capita en paises de Ingresos Bajos e Ingresos Medios-bajos', boxmode = "group")
)
Aviso: Ignoring 3 observationsAviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
Aviso: Ignoring 3 observationsAviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: minimal value for n is 3, returning requested palette with 3 different levels
Aviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
suppressWarnings(
  plot_ly(temp %>% filter(year %in% c(2002, 2012, 2022)), x = ~year, y = ~GDP.PC, color = ~Region, type = "box") %>%
    layout(title = 'PIB per capita segun Region', boxmode = "group")
)
Aviso: Ignoring 3 observationsAviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'
Aviso: Ignoring 3 observationsAviso: 'layout' objects don't have these attributes: 'boxmode'
Valid attributes include:
'_deprecated', 'activeshape', 'annotations', 'autosize', 'autotypenumbers', 'calendar', 'clickmode', 'coloraxis', 'colorscale', 'colorway', 'computed', 'datarevision', 'dragmode', 'editrevision', 'editType', 'font', 'geo', 'grid', 'height', 'hidesources', 'hoverdistance', 'hoverlabel', 'hovermode', 'images', 'legend', 'mapbox', 'margin', 'meta', 'metasrc', 'modebar', 'newshape', 'paper_bgcolor', 'plot_bgcolor', 'polar', 'scene', 'selectdirection', 'selectionrevision', 'separators', 'shapes', 'showlegend', 'sliders', 'smith', 'spikedistance', 'template', 'ternary', 'title', 'transition', 'uirevision', 'uniformtext', 'updatemenus', 'width', 'xaxis', 'yaxis', 'barmode', 'bargap', 'mapType'

Modelos

Filtros para modelo

# variables de etiqueta
ve <- c('country', 'year')
# variables depndientes
vd <- c('hdi')                
               # 'hdi', 'hdi_diff', 'GDP.PC', 'GDP.PC_diff', 'POV', 'POV_diff',

# variables independientes
vi <- c('ODA.PC') 
               # 'ODA.PC', 'ODA.ALL', 'ODA.ALL_diff', 'ODA.PC_diff',       
               # 'ODA.ALL_LOG'

# variables de control
vc <- c('GOV', 'GDP.PC') 
               #  'GROW', 'CC.EST', 'GE.EST', 'PV.EST', 'RQ.EST', 'RL.EST', 'VA.EST', 'GOV', 'GOV_diff'
               #  'GDP.PC', 'POL.CIV.LIB', 'ODA.PC_2', 'ODA.ALL_2', 'ODA.ALL_LOG_2'

# variables interactivas
vint <- c('GOV_GOOD')    # 'GOV_GOOD', 'POL.CIV.LIB_GOOD'

# paises sin datos
delete_c <- c('SS', 'BT', 'ER', 'GW', 'KP', 'LB', 'NG', 'PS', 'SO', 'VU', 'FM', 'KI', 'SB', 'SY')
          #, 'KI',  'MR',   'SD',   'WS' Si se usa POL.CIV.LIB
          #, 'AF', 'CD', 'CI', 'DJ', 'KH', 'LR', 'MR', 'PG', 'ST', 'TJ', 'TL', 'UZ', 'VN', 'WS', 'ZW' Si se usa POV
          #, 'LK', 'PH' Si se usa ODA.ALL_LOG

# años sin datos
first_y <- 2002
last_y <- 2022 # 2018 si se usa POV

f <- paste(vd, '~', case_when(length(vint) > 0 ~ paste(vi, vint, sep = '*'), TRUE ~ vi), '+', paste(vc, collapse = ' + '))

datos_model <- datos_paper %>% 
  filter(!country %in% delete_c, !year <  first_y, !year > last_y) %>%
  select(all_of(c(ve, vd, vi, vc, vint)))

datos_model
vis_dat(datos_model)

Relaciones

Se revisara las relaciones entre las variables graficamente

my_plot = list()

for (vd_ in vd) {
  for (vi_ in c(vi, vc)){
    fit <- lm(paste(vd_, '~', vi_) ,data = datos_model)
    my_plot[[paste(vd_,vi_)]] <- plot_ly(x = datos_model[[vi_]], 
                                         y = datos_model[[vd_]], 
                                         type = 'scatter', 
                                         mode = 'markers', 
                                         name = vi_) %>%
      add_lines(x = datos_model[[vi_]], fitted(fit), name = paste("trace", vi_))
  }
}

subplot(my_plot, nrows = 2, margin = 0.05)  %>% layout(title = vd)
NA

Correr modelos

model_ols <- lm(f, data=datos_model)
model_fe <- plm(f, data=datos_model, index = ve, model = "within")
model_re <- plm(f, data=datos_model, index = ve, model = "random")

Modelo OLS

print(f)
[1] "hdi ~ ODA.PC*GOV_GOOD + GOV + GDP.PC"
summary(model_ols)

Call:
lm(formula = f, data = datos_model)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.228225 -0.045678 -0.000837  0.042303  0.187854 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)      4.615e-01  6.501e-03  70.999  < 2e-16 ***
ODA.PC          -5.542e-05  3.761e-05  -1.474    0.141    
GOV_GOOD         2.180e-02  1.743e-02   1.251    0.211    
GOV              2.711e-02  5.106e-03   5.310 1.28e-07 ***
GDP.PC           6.679e-05  2.142e-06  31.189  < 2e-16 ***
ODA.PC:GOV_GOOD -5.310e-05  6.136e-05  -0.865    0.387    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.07307 on 1317 degrees of freedom
Multiple R-squared:  0.5184,    Adjusted R-squared:  0.5166 
F-statistic: 283.6 on 5 and 1317 DF,  p-value: < 2.2e-16
residualPlots(model_ols)
           Test stat Pr(>|Test stat|)    
ODA.PC        3.2559         0.001159 ** 
GOV_GOOD     -0.5382         0.590510    
GOV          -2.5201         0.011851 *  
GDP.PC      -11.5520        < 2.2e-16 ***
Tukey test   -9.5593        < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

plot(model_ols)

vif(model_ols)
there are higher-order terms (interactions) in this model
consider setting type = 'predictor'; see ?vif
         ODA.PC        GOV_GOOD             GOV          GDP.PC ODA.PC:GOV_GOOD 
       2.359799        3.312239        1.504980        1.261946        4.860636 

Modelo Fixed Effects

print(f)
[1] "hdi ~ ODA.PC*GOV_GOOD + GOV + GDP.PC"
summary(model_fe)
Oneway (individual) effect Within Model

Call:
plm(formula = f, data = datos_model, model = "within", index = ve)

Balanced Panel: n = 63, T = 21, N = 1323

Residuals:
      Min.    1st Qu.     Median    3rd Qu.       Max. 
-0.1031137 -0.0175508  0.0008701  0.0187271  0.1228234 

Coefficients:
                   Estimate  Std. Error t-value  Pr(>|t|)    
ODA.PC           1.0963e-04  2.6502e-05  4.1365 3.761e-05 ***
GOV_GOOD         2.9530e-02  9.1944e-03  3.2117 0.0013530 ** 
GOV              1.7943e-02  5.1958e-03  3.4533 0.0005722 ***
GDP.PC           4.2978e-05  1.5088e-06 28.4849 < 2.2e-16 ***
ODA.PC:GOV_GOOD -1.9176e-04  3.7722e-05 -5.0835 4.268e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Total Sum of Squares:    1.8892
Residual Sum of Squares: 1.0588
R-Squared:      0.43953
Adj. R-Squared: 0.40961
F-statistic: 196.837 on 5 and 1255 DF, p-value: < 2.22e-16
#summary(lm(paste(f, '+ country'), data=datos_model))

Modelo Random Effects

print(f)
[1] "hdi ~ ODA.PC*GOV_GOOD + GOV + GDP.PC"
summary(model_re)
Oneway (individual) effect Random Effect Model 
   (Swamy-Arora's transformation)

Call:
plm(formula = f, data = datos_model, model = "random", index = ve)

Balanced Panel: n = 63, T = 21, N = 1323

Effects:
                    var   std.dev share
idiosyncratic 0.0008437 0.0290465 0.153
individual    0.0046719 0.0683513 0.847
theta: 0.9077

Residuals:
      Min.    1st Qu.     Median    3rd Qu.       Max. 
-0.1010862 -0.0166077  0.0026172  0.0192163  0.1186122 

Coefficients:
                   Estimate  Std. Error z-value  Pr(>|z|)    
(Intercept)      4.7786e-01  9.8844e-03 48.3449 < 2.2e-16 ***
ODA.PC           1.0461e-04  2.6322e-05  3.9744 7.055e-05 ***
GOV_GOOD         3.0137e-02  9.1489e-03  3.2941 0.0009875 ***
GOV              1.9511e-02  5.0565e-03  3.8587 0.0001140 ***
GDP.PC           4.3688e-05  1.4988e-06 29.1486 < 2.2e-16 ***
ODA.PC:GOV_GOOD -1.8419e-04  3.7495e-05 -4.9124 8.996e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Total Sum of Squares:    1.9976
Residual Sum of Squares: 1.1179
R-Squared:      0.44036
Adj. R-Squared: 0.43824
Chisq: 1036.31 on 5 DF, p-value: < 2.22e-16

Hausman Test

print(f)
[1] "hdi ~ ODA.PC*GOV_GOOD + GOV + GDP.PC"
phtest(model_fe, model_re)

    Hausman Test

data:  f
chisq = 17.808, df = 5, p-value = 0.003196
alternative hypothesis: one model is inconsistent

Unit Root Test

df=ur.df(datos_model  %>% filter(country == 'AO') %>% .[[vi]],type="none",lags=0)
df

############################################################### 
# Augmented Dickey-Fuller Test Unit Root / Cointegration Test # 
############################################################### 

The value of the test statistic is: -1.8892 
print('La serie es estacionaria si el valor del estadistico de prueba excede estos valores al 99%, 95% y 90% respectivamente')
[1] "La serie es estacionaria si el valor del estadistico de prueba excede estos valores al 99%, 95% y 90% respectivamente"
qnorm(c(.01,.05,.1)/2)
[1] -2.575829 -1.959964 -1.644854
adf.test(datos_model[[vi]], k= 0)
Aviso: p-value smaller than printed p-value

    Augmented Dickey-Fuller Test

data:  datos_model[[vi]]
Dickey-Fuller = -10.182, Lag order = 0, p-value = 0.01
alternative hypothesis: stationary
y <- data.frame(split(datos_model[[vi]], datos_model$country)) # individuals in columns

purtest(y, pmax = 4, exo = "intercept", test = "madwu")

    Maddala-Wu Unit-Root Test (ex. var.: Individual Intercepts)

data:  y
chisq = 359.5, df = 126, p-value < 2.2e-16
alternative hypothesis: stationarity

Cross-Sectional Dependance

pcdtest(model_fe, test = c("lm"))

    Breusch-Pagan LM test for cross-sectional dependence in panels

data:  hdi ~ ODA.PC * GOV_GOOD + GOV + GDP.PC
chisq = 20259, df = 1953, p-value < 2.2e-16
alternative hypothesis: cross-sectional dependence
pcdtest(model_fe, test = c("cd"))

    Pesaran CD test for cross-sectional dependence in panels

data:  hdi ~ ODA.PC * GOV_GOOD + GOV + GDP.PC
z = 67.307, p-value < 2.2e-16
alternative hypothesis: cross-sectional dependence

Serial Correlation

pbgtest(model_fe)

    Breusch-Godfrey/Wooldridge test for serial correlation in panel models

data:  f
chisq = 924.45, df = 21, p-value < 2.2e-16
alternative hypothesis: serial correlation in idiosyncratic errors

Homoskedasticity

bptest(hdi ~ ODA.PC*GOV_GOOD + GDP.PC + GOV, data = datos_model, studentize = F)

    Breusch-Pagan test

data:  hdi ~ ODA.PC * GOV_GOOD + GDP.PC + GOV
BP = 24.74, df = 5, p-value = 0.0001564
print('alternative hypothesis: Heteroscedasticidad')
[1] "alternative hypothesis: Heteroscedasticidad"

Controlling Heteroskedasticity

coeftest(model_fe)

t test of coefficients:

                   Estimate  Std. Error t value  Pr(>|t|)    
ODA.PC           1.0963e-04  2.6502e-05  4.1365 3.761e-05 ***
GOV_GOOD         2.9530e-02  9.1944e-03  3.2117 0.0013530 ** 
GOV              1.7943e-02  5.1958e-03  3.4533 0.0005722 ***
GDP.PC           4.2978e-05  1.5088e-06 28.4849 < 2.2e-16 ***
ODA.PC:GOV_GOOD -1.9176e-04  3.7722e-05 -5.0835 4.268e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
coeftest(model_fe, vcovHC(model_fe, type = "HC3"))

t test of coefficients:

                   Estimate  Std. Error t value  Pr(>|t|)    
ODA.PC           1.0963e-04  6.1533e-05  1.7816  0.075057 .  
GOV_GOOD         2.9530e-02  1.5307e-02  1.9292  0.053929 .  
GOV              1.7943e-02  1.6301e-02  1.1007  0.271233    
GDP.PC           4.2978e-05  4.7787e-06  8.9935 < 2.2e-16 ***
ODA.PC:GOV_GOOD -1.9176e-04  6.7946e-05 -2.8222  0.004844 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Guardar Data

save(f, delete_c, first_y, last_y, my_plot, model_ols, model_fe, model_re, file = "hdi_ODA.PCGOV_GOOD_GOV_GDP.PC.RData")

Cargar Data

#load("hdi_ODA.PCGOV_GOOD_GOV_GDP.PC_GROW.RData")
#load("hdi_ODA.PCGOV_GOOD_GOV_GDP.PC_POL.CIV.LIB.RData")
#load("hdi_ODA.PCGOV_GOOD_GOV_GDP.PC.RData")
#load("GDP.PC_ODA.PCGOV_GOOD_GOV_GROW.RData")
#load("POV_ODA.PCGOV_GOOD_GOV_GDP.PC_GROW.RData")
load("GOV_ODA.PC_hdi_GDP.PC.RData")
write_xlsx(country_class %>% select(Code, Region, `Income group`) %>% filter(!is.na(Region), !is.na(`Income group`)) %>%
  merge(WDI_data$country, by.x='Code', by.y ='iso3c') %>% select(Code, iso2c, country, Region, `Income group`), 'group income.xls')
LS0tDQp0aXRsZTogIk9mZmljaWFsIERldmVsb3BtZW50IEFzc2lzdGFuY2UgYW5kIEluc3RpdHV0aW9uYWwgUXVhbGl0eSBvbiBVbmRldmVsb3BlZCBjb3VudHJpZXMiDQphdXRob3I6ICJPc2NhciBFZHVhcmRvIE1vcmFsZXMgQ8OhcmRlbmFzIg0KZGF0ZTogIjIwMjQtMDgtMDUiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KIyBTZWNjaW9uZXMgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQojIyBSZWZlcmVuY2lhcw0KDQpJbnRlcm5hdGlvbmFsIGFpZCBtYXkgdGFrZSB0aGUgZm9ybSBvZiBtdWx0aWxhdGVyYWwgYWlkIC0tIHByb3ZpZGVkIHRocm91Z2ggaW50ZXJuYXRpb25hbCBib2RpZXMgc3VjaCBhcyB0aGUgVU4sIG9yIE5HT3Mgc3VjaCBhcyBPeGZhbSAtLSBvciBiaWxhdGVyYWwgYWlkLCB3aGljaCBvcGVyYXRlcyBvbiBhIGdvdmVybm1lbnQtdG8tZ292ZXJubWVudCBiYXNpcy4gVGhlcmUgaXMgY29uc2lkZXJhYmxlIGRlYmF0ZSBhYm91dCB3aGV0aGVyIGludGVybmF0aW9uYWwgYWlkIHdvcmtzLCBpbiB0aGUgc2Vuc2Ugb2YgcmVkdWNpbmcgcG92ZXJ0eSBhbmQgc3RpbXVsYXRpbmcgZGV2ZWxvcG1lbnQuDQoNCkhvd2V2ZXIsIHRoZSBlZmZlY3RpdmVuZXNzIG9mIGFpZCBpcyBvZnRlbiBkaWx1dGVkIGJ5IGNvcnJ1cHRpb24uIEFpZCBpcyBpbnZhcmlhYmx5IGNoYW5uZWxlZCB0aHJvdWdoIHRoZSBnb3Zlcm5tZW50cyBvZiByZWNpcGllbnQgY291bnRyaWVzLCBpbiB3aGljaCBwb3dlciBpcyBvZnRlbiBjb25jZW50cmF0ZWQgaW4gdGhlIGhhbmRzIG9mIGEgZmV3IHBvbGl0aWNpYW5zIGFuZCBidXJlYXVjcmF0cywgYW5kIHRoZSBtZWNoYW5pc21zIG9mIGFjY291bnRhYmlsaXR5IGFyZSwgYXQgYmVzdCwgcG9vcmx5IGRldmVsb3BlZC4gVGhpcyB0ZW5kcyB0byBiZW5lZml0IGNvcnJ1cHQgbGVhZGVycyBhbmQgZWxpdGVzIHJhdGhlciB0aGFuIHRoZSBwZW9wbGUsIHByb2plY3RzIGFuZCBwcm9ncmFtcyBmb3Igd2hpY2ggaXQgd2FzIGludGVuZGVkLg0KDQpfX1dhdHRzLCBDYXJsLiAoMjAxNCkuIFJlOiBEb2VzIGZvcmVpZ24gYWlkIGhlbHAgdGhlIGRldmVsb3BpbmcgY291bnRyaWVzIHRvd2FyZHMgZGV2ZWxvcG1lbnQ/LiBSZXRyaWV2ZWQgZnJvbTpfXyBodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L3Bvc3QvRG9lc19mb3JlaWduX2FpZF9oZWxwX3RoZV9kZXZlbG9waW5nX2NvdW50cmllc190b3dhcmRzX2RldmVsb3BtZW50LzUzMjIwMDVlZDAzOWIxZTc2NDhiNDU5Yy9jaXRhdGlvbi9kb3dubG9hZC4NCg0KVGhlIGh5cG90aGVzaXMgdGhhdCBmb3JlaWduIGFpZCBjYW4gcHJvbW90ZSBncm93dGggaW4gZGV2ZWxvcGluZyBjb3VudHJpZXMgd2FzIGV4cGxvcmVkLCB1c2luZyBwYW5lbCBkYXRhIHNlcmllcyBmb3IgZm9yZWlnbiBhaWQsIHdoaWxlIGFjY291bnRpbmcgZm9yIHJlZ2lvbmFsIGRpZmZlcmVuY2VzIGluIEFzaWFuLCBBZnJpY2FuLCBMYXRpbiBBbWVyaWNhbiwgYW5kIHRoZSBDYXJpYmJlYW4gY291bnRyaWVzIGFzIHdlbGwgYXMgdGhlIGRpZmZlcmVuY2VzIGluIGluY29tZSBsZXZlbHMsIHRoZSByZXN1bHRzIG9mIHRoaXMgc3R1ZHkgYWxzbyBpbmRpY2F0ZSB0aGF0IGZvcmVpZ24gYWlkIGhhcyBtaXhlZCBlZmZlY3RzIG9uIGVjb25vbWljIGdyb3d0aCBpbiBkZXZlbG9waW5nIGNvdW50cmllcy4NCg0KX19Fa2FuYXlha2UsIEUuICYgQ2hhdHJuYSwgRGFzaGEuICgyMDEwKS4gVGhlIGVmZmVjdCBvZiBmb3JlaWduIGFpZCBvbiBlY29ub21pYyBncm93dGggaW4gZGV2ZWxvcGluZyBjb3VudHJpZXMuIEpvdXJuYWwgb2YgSW50ZXJuYXRpb25hbCBCdXNpbmVzcyBhbmQgQ3VsdHVyYWwgU3R1ZGllcy4gMy5fXw0KDQpUaGlzIHN0dWR5IGV4YW1pbmVzIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gZm9yZWlnbiBhaWQsIGluc3RpdHV0aW9uYWwgc3RydWN0dXJlLCBhbmQgZWNvbm9taWMgcGVyZm9ybWFuY2UgZm9yIDgwIGNvdW50cmllcyBpbiBFdXJvcGUsIEFtZXJpY2EsIEFmcmljYSwgYW5kIEFzaWEuIEl0IGlzIGZvdW5kIHRoYXQgb2ZmaWNpYWwgZGV2ZWxvcG1lbnQgYXNzaXN0YW5jZSBhbmQgdGhlIHF1YWxpdHkgb2YgaW5zdGl0dXRpb25hbCBzdHJ1Y3R1cmUgaW4gdGhlIHNhbXBsZSBjb3VudHJpZXMgYWZmZWN0IGVjb25vbWljIGdyb3d0aCBwb3NpdGl2ZWx5Lg0KDQpfX0hheWFsb8SfbHUsIFDEsW5hci4gKDIwMjMpLiBGb3JlaWduIEFpZCwgSW5zdGl0dXRpb25zLCBhbmQgRWNvbm9taWMgUGVyZm9ybWFuY2UgaW4gRGV2ZWxvcGluZyBDb3VudHJpZXMuIEVza2nFn2VoaXIgT3NtYW5nYXppIMOcbml2ZXJzaXRlc2kgxLBrdGlzYWRpIHZlIMSwZGFyaSBCaWxpbWxlciBEZXJnaXNpLiAxOC4gNzQ4LTc2NS4gMTAuMTcxNTMvb2d1aWliZi4xMjc3MzQ4Ll9fDQoNCiMjIE1hbnVhbCBwYXJhIHJlcGxpY2FyDQoNCiMjIyBDYXJnYW5kbyBMaWJyZXJpYXMNCg0KQWxndW5hcyBsaWJyZXJpYXMgeSBwYXF1ZXRlcyB1c2Fkb3MgcGFyYSBvYnRlbmVyIHkgZGVzY2FyZ2FyIGxvcyBkYXRvcw0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKSAjIG1hbmVqbyBkZSBkYXRhZnJhbWVzDQpsaWJyYXJ5KHJlc2hhcGUyKSAgIyBwYXJhIHRyYW5mcm9tYXIgZGF0YSBkZSBsb25nIGEgd2lkZQ0KbGlicmFyeShXREkpICAgICAgICMgbGlicmVyaWEgcGFyYSBhY2NlZGVyIGEgbWV0YWRhdGEgZGUgYmFuY28gbXVuZGlhbA0KbGlicmFyeShyZWFkeGwpICAgICMgbGVlciBhcmNoaXZvcyBkZSBleGNlbA0KbGlicmFyeShyZWFkcikgICAgICMgbGVlciBhcmNoaXZvcyBjc3YNCmxpYnJhcnkodmlzZGF0KSAgICAjIHZpc3VhbGl6YWNpb24gZGUgZGF0b3MgY29tbyBncmFmaWNvcw0KbGlicmFyeShwbG90bHkpICAgICMgZ3JhZmljb3MNCmxpYnJhcnkocHVycnIpICAgICAjIGZ1bmNpb24gbWFwDQpsaWJyYXJ5KHBsbSkgICAgICAgIyBtb2RlbG9zIGxpbmVhbGVzIHBhcmEgZGF0b3MgcGFuZWwNCmxpYnJhcnkoY2FyKSAgICAgICAjIHRlc3QgeSB1dGlsaWRhZGVzIHBhcmEgbW9kZWxvcw0KbGlicmFyeShodG1sdG9vbHMpICMgcGFyYSBpbXByaW1pciBncmFmaWNvcyBlbiBodG1sDQpsaWJyYXJ5KHVyY2EpICAgICAgIyBVbml0IHJvb3QgdGVzdA0KbGlicmFyeSh0c2VyaWVzKSAgICMgRGlja2V5IEZ1bGxlciB0ZXN0IChzZXJpZSBlc3RhY2lvbmFyaWEpDQpsaWJyYXJ5KGxtdGVzdCkgICAgIyBQcnVlYmFzIGRlIG1vZGVsb3MgbGluZWFsZXMNCmBgYA0KDQojIyMgT2J0ZW5lciBkYXRvcw0KDQpEYXRvcyBwYXJhIHBhaXNlcyBiYWpvcyBpbmdyZXNvcyBzZWFuIHV0aWxpemFkb3MsIHNlZ3VuIGNsYXNpZmljYWNpw7NuIGRlbCBiYW5jbyBtdW5kaWFsLCBoYXkgMjYgcGFpc2VzIGRlIGJham9zIGluZ3Jlc29zIHkgNTEgZGUgaW5ncmVzb3MgbWVkaW9zIGJham9zDQoNCmBgYHtyfQ0KY291bnRyeV9jbGFzcyA8LSByZWFkX2V4Y2VsKCJDTEFTUy54bHN4IikNCg0KY291bnRyeV9jbGFzcyAlPiUNCiAgZmlsdGVyKCFpcy5uYShSZWdpb24pLCAhaXMubmEoYEluY29tZSBncm91cGApKSAlPiUNCiAgZ3JvdXBfYnkoYEluY29tZSBncm91cGApICU+JQ0KICBzdW1tYXJpc2UoY291bnRyaWVzID0gbigpKSAlPiUNCiAgYXJyYW5nZShmYWN0b3IoYEluY29tZSBncm91cGAsIGxldmVscyA9IGMoJ0hpZ2ggaW5jb21lJywgJ1VwcGVyIG1pZGRsZSBpbmNvbWUnLCAnTG93ZXIgbWlkZGxlIGluY29tZScsICdMb3cgaW5jb21lJykpKQ0KYGBgDQoNCkxpc3RhZG8gZGUgcGFpc2VzIGEgYW5hbGlzYXI6DQoNCmBgYHtyfQ0KbXlfY291bnRyaWVzIDwtIGNvdW50cnlfY2xhc3MgJT4lDQogIGZpbHRlcighaXMubmEoUmVnaW9uKSwgYEluY29tZSBncm91cGAgJWluJSBjKCdMb3cgaW5jb21lJywgJ0xvd2VyIG1pZGRsZSBpbmNvbWUnKSkgJT4lDQogIHNlbGVjdChDb2RlKQ0KbXlfY291bnRyaWVzICU+JSBtZXJnZShjb3VudHJ5X2NsYXNzKSAlPiUgc2VsZWN0KENvZGUsIEVjb25vbXkpDQpgYGANCg0KSGFjZXIgbGEgcmVzcGVjdGl2YSBhc29jaWFjaW9uIGRlIG5vbWJyZXMgaXNvM2MgZSBpc28yYw0KDQpgYGB7cn0NCm15X2NvdW50cmllcyRpc28yYyA8LSBXRElfZGF0YSRjb3VudHJ5ICU+JQ0KICBmaWx0ZXIoaXNvM2MgJWluJSBteV9jb3VudHJpZXMkQ29kZSkgJT4lDQogIC4kaXNvMmMNCmBgYA0KDQpEYXRvcyBkZWwgYmFuY28gbXVuZGlhbCAocGFyYSBPREEgeSBsb3MgaW5kaWNlcyBkZSBnb2Jlcm5hbnphKSB5IGVsIEh1bWFuIERldmVsb3BtZW50IFJlcG9ydHMgQVBJIHNvbiBkZXNjYXJnYWRvcyBkZXNkZSBzY3JpcHRzIGRlIFB5dGhvbi4gU29uIGFsbWFjZW5hZG9zIGVuIGFyY2hpdm9zIENTViB5IGx1ZWdvIHNvbiBjYXJnYWRvcyBhcXVpOg0KDQojIyMgY2FyZ2FyIEhESQ0KDQpgYGB7cn0NCmRhdG9zX0hESSA8LSByZWFkX2NzdigiZGF0b3NfcHl0aG9uX0hESS5jc3YiLCBjb2xfbmFtZXMgPSBjKCdDb2RlJywgJ2lzbzJjJywgJ2luZGljYXRvcicsICd5ZWFyJywgJ3ZhbHVlJyksIA0KICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGxpc3QoY29sX2NoYXJhY3RlcigpLCBjb2xfY2hhcmFjdGVyKCksIGNvbF9jaGFyYWN0ZXIoKSwgY29sX2RvdWJsZSgpLCBjb2xfZG91YmxlKCkpKQ0KDQpoZGlfaW5kaWNhdG9ycyA8LSBjKCdoZGknKSAjZGF0b3NfSERJICU+JSBkaXN0aW5jdChpbmRpY2F0b3IpICU+JSAuJGluZGljYXRvcg0KZGF0b3NfSERJIDwtIGRhdG9zX0hESSAlPiUgZmlsdGVyKGluZGljYXRvciAlaW4lIGhkaV9pbmRpY2F0b3JzKQ0KYGBgDQoNCiMjIyBjYXJnYXIgT0RBLCBHRFAsIFBPUC5HUk9XDQoNCmBgYHtyfQ0Kb2RhX2luZGljYXRvcnMgPC0gYygNCidEVF9PREFfQUxMRF9DRCcsDQojJ0RUX09EQV9BTExEX0tEJywNCiMnRFRfT0RBX09BVExfQ0QnLA0KIydEVF9PREFfT0FUTF9LRCcsDQojJ0RUX09EQV9PREFUX0NEJywNCiMnRFRfT0RBX09EQVRfR0lfWlMnLA0KIydEVF9PREFfT0RBVF9HTl9aUycsDQojJ0RUX09EQV9PREFUX0tEJywNCiMnRFRfT0RBX09EQVRfTVBfWlMnLA0KJ0RUX09EQV9PREFUX1BDX1pTJyMsDQojJ0RUX09EQV9PREFUX1hQX1pTJw0KKQ0KZ29iX2luZGljYXRvcnMgPC0gYygNCidDQ19FU1QnLA0KIydDQ19OT19TUkMnLA0KIydDQ19QRVJfUk5LJywNCiMnQ0NfUEVSX1JOS19MT1dFUicsDQojJ0NDX1BFUl9STktfVVBQRVInLA0KIydDQ19TVERfRVJSJywNCidHRV9FU1QnLA0KIydHRV9OT19TUkMnLA0KIydHRV9QRVJfUk5LJywNCiMnR0VfUEVSX1JOS19MT1dFUicsDQojJ0dFX1BFUl9STktfVVBQRVInLA0KIydHRV9TVERfRVJSJywNCidQVl9FU1QnLA0KIyAnUFZfTk9fU1JDJywNCiMgJ1BWX1BFUl9STksnLA0KIyAnUFZfUEVSX1JOS19MT1dFUicsDQojICdQVl9QRVJfUk5LX1VQUEVSJywNCiMgJ1BWX1NURF9FUlInLA0KJ1JRX0VTVCcsDQojICdSUV9OT19TUkMnLA0KIyAnUlFfUEVSX1JOSycsDQojICdSUV9QRVJfUk5LX0xPV0VSJywNCiMgJ1JRX1BFUl9STktfVVBQRVInLA0KIyAnUlFfU1REX0VSUicsDQonUkxfRVNUJywNCiMgJ1JMX05PX1NSQycsDQojICdSTF9QRVJfUk5LJywNCiMgJ1JMX1BFUl9STktfTE9XRVInLA0KIyAnUkxfUEVSX1JOS19VUFBFUicsDQojICdSTF9TVERfRVJSJywNCidWQV9FU1QnIywNCiMgJ1ZBX05PX1NSQycsDQojICdWQV9QRVJfUk5LJywNCiMgJ1ZBX1BFUl9STktfTE9XRVInLA0KIyAnVkFfUEVSX1JOS19VUFBFUicsDQojICdWQV9TVERfRVJSJw0KKQ0KZ2RwX2luZGljYXRvcnMgPC0gYygNCiMgJ05ZX0FESl9OTlRZX1BDX0NEJywNCiMgJ05ZX0FESl9OTlRZX1BDX0tEJywNCiMgJ05ZX0FESl9OTlRZX1BDX0tEX1pHJywNCiMgJ05ZX0dEUF9QQ0FQX0NOJywNCiMgJ05ZX0dEUF9QQ0FQX0tOJywNCidOWV9HRFBfUENBUF9DRCcsDQojICdOWV9HRFBfUENBUF9LRCcsDQojICdOWV9HRFBfTUtUUF9LRF9aRycsDQojICdOWV9HRFBfREVGTF9aU19BRCcsDQojICdOWV9HRFBfREVGTF9aUycsDQojICdOWV9HRFBfTUtUUF9DRCcsDQojICdOWV9HRFBfTUtUUF9DTicsDQojICdOWV9HRFBfTUtUUF9LTicsDQojICdOWV9HRFBfTUtUUF9LRCcsDQojICdOWV9HRFBfUENBUF9LRF9aRycsDQojICdOWV9HRFBfUENBUF9QUF9LRCcsDQojICdOWV9HRFBfUENBUF9QUF9DRCcsDQojICdTTF9HRFBfUENBUF9FTV9LRCcsDQonU1BfUE9QX0dST1cnDQopDQoNCmRhdG9zX1dCIDwtIGRhdGEuZnJhbWUoaW5kaWNhdG9yID0gY2hhcmFjdGVyKCksIGlzbzJjID0gY2hhcmFjdGVyKCksIHllYXIgPSBkb3VibGUoKSwgdmFsdWUgPSBkb3VibGUoKSkNCg0Kc3VwcHJlc3NXYXJuaW5ncygNCiAgZm9yIChpbmRpY2F0b3IgaW4gYyhvZGFfaW5kaWNhdG9ycywgZ29iX2luZGljYXRvcnMsIGdkcF9pbmRpY2F0b3JzKSkgew0KICAgIGRhdG9zX1dCIDwtIHJiaW5kKGRhdG9zX1dCLCByZWFkX2NzdihwYXN0ZSgiZGF0b3NfcHl0aG9uIiwgaW5kaWNhdG9yLCAiLmNzdiIsIHNlcCA9JycpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCdpbmRpY2F0b3InLCAnaXNvMmMnLCAneWVhcicsICd2YWx1ZScpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGxpc3QoY29sX2NoYXJhY3RlcigpLCBjb2xfY2hhcmFjdGVyKCksIGNvbF9kb3VibGUoKSwgY29sX2RvdWJsZSgpKSkpDQogIH0NCikNCmBgYA0KDQojIyMgY2FyZ2FyIFBPVkVSVFkNCmBgYHtyfQ0KUG92ZXJ0eSA8LSByZWFkX2V4Y2VsKCJHbG9iYWxFeHRyZW1lUG92ZXJ0eURvbGxhcmFEYXlfQ29tcGFjdC54bHN4Iiwgc2hlZXQgPSAiRGF0YSBMb25nIEZvcm1hdCIpDQoNCm5hbWVzKFBvdmVydHkpIDwtIGMoImNjb2RlIiwgImNvdW50cnkiLCAieWVhciIsICJ2YWx1ZSIpDQoNClBvdmVydHlbUG92ZXJ0eT09IkNhcGUgVmVyZGUiXSA8LSAiQ2FibyBWZXJkZSINClBvdmVydHlbUG92ZXJ0eT09IkNvbmdvIl0gPC0gIkNvbmdvLCBSZXAuIg0KUG92ZXJ0eVtQb3ZlcnR5PT0iRWd5cHQiXSA8LSAiRWd5cHQsIEFyYWIgUmVwLiINClBvdmVydHlbUG92ZXJ0eT09IklyYW4iXSA8LSAiSXJhbiwgSXNsYW1pYyBSZXAuIg0KUG92ZXJ0eVtQb3ZlcnR5PT0iS3lyZ3l6c3RhbiJdIDwtICJLeXJneXogUmVwdWJsaWMiDQpQb3ZlcnR5W1BvdmVydHk9PSJMYW9zIl0gPC0gIkxhbyBQRFIiDQpQb3ZlcnR5W1BvdmVydHk9PSJNYWNlZG9uaWEiXSA8LSAiTm9ydGggTWFjZWRvbmlhIg0KUG92ZXJ0eVtQb3ZlcnR5PT0iUnVzc2lhIl0gPC0gIlJ1c3NpYW4gRmVkZXJhdGlvbiINClBvdmVydHlbUG92ZXJ0eT09IlNsb3Zha2lhIl0gPC0gIlNsb3ZhayBSZXB1YmxpYyINClBvdmVydHlbUG92ZXJ0eT09IlNvdXRoIEtvcmVhIl0gPC0gIktvcmVhLCBSZXAuIg0KUG92ZXJ0eVtQb3ZlcnR5PT0iU3dhemlsYW5kIl0gPC0gIkVzd2F0aW5pIg0KUG92ZXJ0eVtQb3ZlcnR5PT0iU3lyaWEiXSA8LSAiU3lyaWFuIEFyYWIgUmVwdWJsaWMiDQpQb3ZlcnR5W1BvdmVydHk9PSJUaGUgR2FtYmlhIl0gPC0gIkdhbWJpYSwgVGhlIg0KUG92ZXJ0eVtQb3ZlcnR5PT0iVHVya2V5Il0gPC0gIlR1cmtpeWUiDQpQb3ZlcnR5W1BvdmVydHk9PSJWZW5lenVlbGEiXSA8LSAiVmVuZXp1ZWxhLCBSQiINClBvdmVydHlbUG92ZXJ0eT09IlllbWVuIl0gPC0gIlllbWVuLCBSZXAuIg0KDQpQb3ZlcnR5IDwtIFBvdmVydHkgJT4lDQogIGZpbHRlcih5ZWFyID4gMTk5NCkgJT4lDQogIG1lcmdlKFdESV9kYXRhJGNvdW50cnksIGFsbC54ID0gVFJVRSkgJT4lDQogIG11dGF0ZShpbmRpY2F0b3IgPSAnUE9WJykgJT4lDQogIG1lcmdlKG15X2NvdW50cmllcykgJT4lDQogIHNlbGVjdChpbmRpY2F0b3IsIGlzbzJjLCB5ZWFyLCB2YWx1ZSkNCg0KYGBgDQoNCiMjIyBjYXJnYXIgUG9saXRpY2FsIENpdmlsIExpYmVydGllcw0KYGBge3J9DQpQQ19MSUIgPC0gcmVhZF9jc3YoInBvbGl0aWNhbC1jaXZpbC1saWJlcnRpZXMtaW5kZXguY3N2IikNCg0KUENfTElCIDwtIFBDX0xJQiAlPiUNCiAgZmlsdGVyKHllYXIgPiAxOTk0LCAhaXMubmEoQ29kZSkpICU+JQ0KICBtZXJnZShteV9jb3VudHJpZXMpICU+JQ0KICBtdXRhdGUoaW5kaWNhdG9yID0gJ1BPTC5DSVYuTElCJykgJT4lDQogIHNlbGVjdChpbmRpY2F0b3IsIGlzbzJjLCB5ZWFyLCB2YWx1ZSkNCmBgYA0KDQoNCiMjIyBNYW5pcHVsYWNpb24gZGUgRGF0b3MNCg0KIyMjIyBUcmFuc2Zvcm1hciBkYXRvcyBhIGxhIGVzdHJ1Y3R1cmEgd2lkZQ0KYGBge3J9DQpkYXRvc19wYXBlciA8LSByYmluZChkYXRvc19XQiwgZGF0b3NfSERJICU+JSBzZWxlY3QoaW5kaWNhdG9yLCBpc28yYywgeWVhciwgdmFsdWUpLCBQb3ZlcnR5LCBQQ19MSUIpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW5kaWNhdG9yLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKQ0KYGBgDQoNCiMjIyMgUHJvbWVkaW8gZGUgSW5kaWNlcyBkZSBHb2Jlcm5hbnphDQpgYGB7cn0NCmRhdG9zX3BhcGVyIDwtIGRhdG9zX3BhcGVyICU+JSBtdXRhdGUoR09WID0gIChDQy5FU1QgKyBHRS5FU1QgKyBQVi5FU1QgKyBSUS5FU1QgKyBSTC5FU1QgKyBWQS5FU1QpIC8gNikNCmBgYA0KDQojIyMjIE9wZXJhZG9yIERpZmVyZW5jaWENCg0KYGBge3J9DQpkYXRvc19wYXBlciA8LSBkYXRvc19wYXBlciAlPiUgYXJyYW5nZShpc28yYywgeWVhcikgJT4lIA0KICAgICAgICBtdXRhdGUoaGRpX2RpZmYgPSBjYXNlX3doZW4oaXNvMmMgPT0gZHBseXI6OmxhZyhpc28yYykgfiBoZGkgLSBkcGx5cjo6bGFnKGhkaSksIFRSVUUgfiBOQV9yZWFsXyksIA0KICAgICAgICAgICAgICAgTlkuR0RQLlBDQVAuQ0RfZGlmZiA9IGNhc2Vfd2hlbihpc28yYyA9PSBkcGx5cjo6bGFnKGlzbzJjKSB+IE5ZLkdEUC5QQ0FQLkNEIC0gZHBseXI6OmxhZyhOWS5HRFAuUENBUC5DRCksIFRSVUUgfiBOQV9yZWFsXyksDQogICAgICAgICAgICAgICBEVC5PREEuQUxMRC5DRF9kaWZmID0gY2FzZV93aGVuKGlzbzJjID09IGRwbHlyOjpsYWcoaXNvMmMpIH4gRFQuT0RBLkFMTEQuQ0QgLSBkcGx5cjo6bGFnKERULk9EQS5BTExELkNEKSwgVFJVRSB+IE5BX3JlYWxfKSwNCiAgICAgICAgICAgICAgIERULk9EQS5PREFULlBDLlpTX2RpZmYgPSBjYXNlX3doZW4oaXNvMmMgPT0gZHBseXI6OmxhZyhpc28yYykgfiBEVC5PREEuT0RBVC5QQy5aUyAtIGRwbHlyOjpsYWcoRFQuT0RBLk9EQVQuUEMuWlMpLCBUUlVFIH4gTkFfcmVhbF8pLA0KICAgICAgICAgICAgICAgR09WX2RpZmYgPSBjYXNlX3doZW4oaXNvMmMgPT0gZHBseXI6OmxhZyhpc28yYykgfiBHT1YgLSBkcGx5cjo6bGFnKEdPViksIFRSVUUgfiBOQV9yZWFsXyksDQogICAgICAgICAgICAgICBQT1ZfZGlmZiA9IGNhc2Vfd2hlbihpc28yYyA9PSBkcGx5cjo6bGFnKGlzbzJjKSB+IFBPViAtIGRwbHlyOjpsYWcoUE9WKSwgVFJVRSB+IE5BX3JlYWxfKSkNCmBgYA0KDQojIyMjIENsYXNpZmljYWNpb25lcyBkaWNvdG9taWNhcw0KYGBge3J9DQpkYXRvc19wYXBlciA8LSBkYXRvc19wYXBlciAlPiUgbXV0YXRlKEdPVl9HT09EID0gY2FzZV93aGVuKEdPViA+PSAwIH4gMSwgVFJVRSB+IDApKQ0KcGxvdF9seShkYXRhID0gZGF0b3NfcGFwZXIgJT4lIGZpbHRlcighaXMubmEoR09WKSksIHkgPSB+IEdPViwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdtYXJrZXJzJykgJT4lDQogIGxheW91dCh0aXRsZSA9ICdJbmRpY2UgcHJvbWVkaW8gZGUgZ29iZXJuYW56YScsIHhheGlzID0gbGlzdCh0aXRsZSA9ICdSZWdpc3Ryb3MnKSkNCg0KZGF0b3NfcGFwZXIgPC0gZGF0b3NfcGFwZXIgJT4lIG11dGF0ZShQT0wuQ0lWLkxJQl9HT09EID0gY2FzZV93aGVuKFBPTC5DSVYuTElCID49IDAuNSB+IDEsIFRSVUUgfiAwKSkNCnBsb3RfbHkoZGF0YSA9IGRhdG9zX3BhcGVyICU+JSBmaWx0ZXIoIWlzLm5hKFBPTC5DSVYuTElCKSksIHkgPSB+IFBPTC5DSVYuTElCLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ21hcmtlcnMnKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gJ0luZGljZSBsaWJlcnRhZGVzIHBvbGl0aWNhcyB5IGNpdmlsZXMnLCB4YXhpcyA9IGxpc3QodGl0bGUgPSAnUmVnaXN0cm9zJykpDQpgYGANCg0KIyMjIyBWYXJpYWJsZXMgbG9nYXJpdG1vDQpgYGB7cn0NCmRhdG9zX3BhcGVyIDwtIGRhdG9zX3BhcGVyICU+JSBtdXRhdGUoRFQuT0RBLkFMTEQuQ0RfTE9HID0gbG9nKERULk9EQS5BTExELkNEKSkNCmBgYA0KDQojIyMjIFZhcmlhYmxlcyBjdWFkcmFkYXMNCmBgYHtyfQ0KZGF0b3NfcGFwZXIgPC0gZGF0b3NfcGFwZXIgJT4lIG11dGF0ZShEVC5PREEuT0RBVC5QQy5aU18yID0gRFQuT0RBLk9EQVQuUEMuWlMgXiAyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEVC5PREEuQUxMRC5DRF8yID0gRFQuT0RBLkFMTEQuQ0QgXiAyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEVC5PREEuQUxMRC5DRF9MT0dfMiA9IERULk9EQS5BTExELkNEX0xPRyBeIDIsKQ0KYGBgDQoNCiMjIyMgQ29sb2NhciBub21icmVzIGEgdmFyaWFibGVzDQpgYGB7cn0NCm5hbWVzKGRhdG9zX3BhcGVyKSA8LSBjKCdjb3VudHJ5JywneWVhcicsJ09EQS5BTEwnLCdPREEuUEMnLCdDQy5FU1QnLCdHRS5FU1QnLCdQVi5FU1QnLCdSUS5FU1QnLCdSTC5FU1QnLCdWQS5FU1QnLCdHRFAuUEMnLCdHUk9XJywnaGRpJywnUE9WJywnUE9MLkNJVi5MSUInLCdHT1YnLCdoZGlfZGlmZicsJ0dEUC5QQ19kaWZmJywnT0RBLkFMTF9kaWZmJywnT0RBLlBDX2RpZmYnLCdHT1ZfZGlmZicsJ1BPVl9kaWZmJywnR09WX0dPT0QnLCdQT0wuQ0lWLkxJQl9HT09EJywnT0RBLkFMTF9MT0cnLCdPREEuUENfMicsJ09EQS5BTExfMicsJ09EQS5BTExfTE9HXzInKQ0KYGBgDQoNCg0KDQojIyMjIFZpc3VhbGl6YWNpb24gZGUgRGF0b3MgIHsudGFic2V0IC50YWJzZXQtZmFkZX0NCg0KIyMjIyMgT0RBDQoNCmBgYHtyfQ0KdmlzX2RhdChkYXRvc19wYXBlciAlPiUgc2VsZWN0KE9EQS5BTEwsIE9EQS5QQykpIA0KICAjIERULk9EQS5PQVRMLkNEIGFuZCBEVC5PREEuT0FUTC5LRCBmYWx0YW4NCiAgIyBEVC5PREEuT0RBVC5HSS5aUywgRFQuT0RBLk9EQVQuR04uWlMsIERULk9EQS5PREFULk1QLlpTIGFuZCBEVC5PREEuT0RBVC5YUC5aUyB0aWVuZW4gZmFsdGFzDQogICMgVW4gcGFyIGRlIG9jdXJyZW5jaWFzIHBhaXMtYcOxbyBxdWUgZmFsdGFuIGRhdG9zDQpgYGANCg0KIyMjIyMgR0RQDQoNCmBgYHtyfQ0KdmlzX2RhdChkYXRvc19wYXBlciAlPiUgc2VsZWN0KEdEUC5QQykpIA0KICAjIE5ZLkdEUC5QQ0FQLkNOLCBHRFAuUEMsIE5ZLkdEUC5NS1RQLkNELCBOWS5HRFAuTUtUUC5DTiBzb24gYnVlbm9zIGNhbmRpZGF0b3MgcGFyYSB1c2FyIGNvbW8gdmFyaWFibGVzLCANCiAgIyAnU1knZmFsdGEgUElCIHBlciBDYXBpdGEgZW4gMjAyMiwgMjAyMyBzaW4gZGF0b3MgYWxndW5vcyBwYWlzZXMNCmBgYA0KDQojIyMjIyBHT1YNCg0KYGBge3J9DQp2aXNfZGF0KGRhdG9zX3BhcGVyICU+JSBhcnJhbmdlKHllYXIpICU+JSBzZWxlY3QoYWxsX29mKGdzdWIoIl8iLCAiLiIsIGdvYl9pbmRpY2F0b3JzKSkpKSANCiAgIyBEYXRvcyBkZWwgMjAwMCBwYXJhIGF0cmFzIHRpZW5lbiBlc3BhY2lvcyBmYWx0YW50ZXMgDQpgYGANCg0KIyMjIyMgSERJDQoNCmBgYHtyfQ0KdmlzX2RhdChkYXRvc19wYXBlciAlPiUgYXJyYW5nZSh5ZWFyKSAlPiUgc2VsZWN0KGFsbF9vZihoZGlfaW5kaWNhdG9ycykpKSANCiAgIyBhYnIsIGNvMl9wcm9kLCBsZSwgbGVfZiwgbGVfbSwgbW1yIHNvbiBsYXMgcG9jYXMgY2F0ZWdvcmlhcyBzaW4gZGF0b3MgZmFsdGFudGVzDQogICMgaGRpIGZhbHRhbnRlIGVuIG11bHRpcGxlcyBvY2FjaW9uZXMNCmBgYA0KDQojIyMjIyBQT1AuR1JPVw0KDQpgYGB7cn0NCnZpc19kYXQoZGF0b3NfcGFwZXIgJT4lIGFycmFuZ2UoY291bnRyeSkgJT4lIHNlbGVjdChHUk9XKSkNCmBgYA0KDQojIyMjIyBQT1YgDQoNCmBgYHtyfQ0KdmlzX2RhdChkYXRvc19wYXBlciAlPiUgYXJyYW5nZSh5ZWFyLCBjb3VudHJ5KSAlPiUgc2VsZWN0KFBPVikpDQoNCiMgJ0FGJywgJ0NEJywgJ0NJJywgJ0RKJywgJ0tIJywgJ0xSJywgJ01SJywgJ1BHJywgJ1NUJywgJ1RKJywgJ1VaJywgJ1ZOJywgJ1dTJyBubyB0aWVuZW4gZGF0b3MgZGUgZXN0YSB2YXJpYWJsZQ0KIyBQb3JjZW50YWplIGRlIHBlcnNvbmFzIHBvciBkZWJham8gZGUgbGEgbGluZWEgZGUgZXh0cmVtYSBwb2JyZXphIChEb2xsYXIgYSBkYXkpDQpgYGANCg0KIyMjIyMgUE9MSVRJQ0FMIENJVklMIExJQkVSVFkNCg0KYGBge3J9DQp2aXNfZGF0KGRhdG9zX3BhcGVyICU+JSBhcnJhbmdlKGNvdW50cnkpICU+JSBzZWxlY3QoUE9MLkNJVi5MSUIpKSANCiAgIyBLSQlNUglTRAlXUyAgc29uIHBhaXNlcyBzaW4gZGF0b3MgcGFyYSBlc3RvcyBhw7Fvcw0KYGBgDQoNCiMjIFRhYmxhcyBpbmZvcm1hdGl2YXMNCmBgYHtyfQ0KdGVtcCA8LSBkYXRvc19wYXBlciAlPiUgDQogICBmaWx0ZXIoIXllYXIgPCAgMjAwMiwgIXllYXIgPiAyMDIyLCAhY291bnRyeSAlaW4lIGMoJ1NTJykpICU+JQ0KICAgbWVyZ2UobXlfY291bnRyaWVzLCBieS54ID0gImNvdW50cnkiLCBieS55ID0gImlzbzJjIikgJT4lDQogICBtZXJnZShjb3VudHJ5X2NsYXNzKSAlPiUNCiAgIGdyb3VwX2J5KGBJbmNvbWUgZ3JvdXBgKSAlPiUNCiAgIHN1bW1hcmlzZSgnMjAwMiAtIDIwMjInID0gc3VtKE9EQS5BTEwpKQ0KDQp0ZW1wDQoNCnBsb3RfbHkodGVtcCAlPiUgDQogICAgICAgICAgbXV0YXRlKGBJbmNvbWUgZ3JvdXBgID0gY2FzZV93aGVuKGBJbmNvbWUgZ3JvdXBgID09ICdMb3cgaW5jb21lJyB+ICdJbmdyZXNvcyBCYWpvcycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBJbmNvbWUgZ3JvdXBgID09ICdMb3dlciBtaWRkbGUgaW5jb21lJyB+ICdJbmdyZXNvcyBNZWRpb3MtYmFqb3MnKSksDQogICAgICAgIGxhYmVscyA9IH5gSW5jb21lIGdyb3VwYCwgdmFsdWVzID0gfmAyMDAyIC0gMjAyMmAsIHR5cGUgPSAncGllJywgdGV4dGluZm8gPSAnbGFiZWwrcGVyY2VudCcpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAnQXNpc3RlbmNpYSBPZmljaWFsIHBhcmEgZWwgRGVzYXJyb2xsbyByZWNpYmlkYSB0b3RhbCAyMDAyIC0gMjAyMicsDQogICAgICAgICBwbG90X2JnY29sb3IgPSAiI2U1ZWNmNiIpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQp0ZW1wIDwtIGRhdG9zX3BhcGVyICU+JSANCiAgbXV0YXRlKHlfcmFuZ2UgPSBjYXNlX3doZW4oeWVhciA8IDIwMDcgfiAnMjAwMiAtIDIwMDYnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyIDwgMjAxMiB+ICcyMDA3IC0gMjAxMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPCAyMDE3IH4gJzIwMTIgLSAyMDE2JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICcyMDE3IC0gMjAyMicpKSAlPiUNCiAgZmlsdGVyKCF5ZWFyIDwgIDIwMDIsICF5ZWFyID4gMjAyMiwgIWNvdW50cnkgJWluJSBjKCdTUycpKSAlPiUNCiAgbWVyZ2UobXlfY291bnRyaWVzLCBieS54ID0gImNvdW50cnkiLCBieS55ID0gImlzbzJjIikgJT4lDQogIG1lcmdlKGNvdW50cnlfY2xhc3MpICU+JQ0KICBncm91cF9ieShgSW5jb21lIGdyb3VwYCwgeV9yYW5nZSkgJT4lDQogIHN1bW1hcmlzZShzdW09c3VtKE9EQS5BTEwpLCAuZ3JvdXBzID0gImRyb3AiKQ0KDQp0ZW1wICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tID0geV9yYW5nZSwgdmFsdWVzX2Zyb20gPSBzdW0pDQoNCnBsb3RfbHkodGVtcCAlPiUgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGBJbmNvbWUgZ3JvdXBgLCB2YWx1ZXNfZnJvbSA9IHN1bSksIA0KICAgICAgICB4ID0gfnlfcmFuZ2UsIHkgPSB+YExvd2VyIG1pZGRsZSBpbmNvbWVgLCBuYW1lID0gJ0luZ3Jlc29zIE1lZGlvcy1iYWpvcycsIHR5cGUgPSAnYmFyJykgJT4lIA0KICBhZGRfdHJhY2UoeSA9IH5gTG93IGluY29tZWAsIG5hbWUgPSAnSW5ncmVzb3MgQmFqb3MnKSAlPiUgDQogIGxheW91dCh0aXRsZSA9ICdBc2lzdGVuY2lhIE9maWNpYWwgcGFyYSBlbCBEZXNhcnJvbGxvIHJlY2liaWRhIHRvdGFsJywNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdEb2xhcmVzIEFjdHVhbGVzJyksIHhheGlzID0gbGlzdCh0aXRsZSA9ICdQZXJpb2RvJyksIGJhcm1vZGUgPSAnZ3JvdXAnKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KdGVtcCA8LSBkYXRvc19wYXBlciAlPiUgDQogIGZpbHRlcigheWVhciA8ICAyMDAyLCAheWVhciA+IDIwMjIsICFjb3VudHJ5ICVpbiUgYygnU1MnKSkgJT4lDQogIG1lcmdlKG15X2NvdW50cmllcywgYnkueCA9ICJjb3VudHJ5IiwgYnkueSA9ICJpc28yYyIpICU+JQ0KICBtZXJnZShjb3VudHJ5X2NsYXNzKSAlPiUNCiAgZ3JvdXBfYnkoUmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKCcyMDAyIC0gMjAyMicgPSBzdW0oT0RBLkFMTCkpDQoNCnRlbXANCg0KcGxvdF9seSh0ZW1wLCBsYWJlbHMgPSB+UmVnaW9uLCB2YWx1ZXMgPSB+YDIwMDIgLSAyMDIyYCwgdHlwZSA9ICdwaWUnLCB0ZXh0aW5mbyA9ICdsYWJlbCtwZXJjZW50JykgJT4lDQogIGxheW91dCh0aXRsZSA9ICdBc2lzdGVuY2lhIE9maWNpYWwgcGFyYSBlbCBEZXNhcnJvbGxvIHJlY2liaWRhIHRvdGFsIDIwMDIgLSAyMDIyJywNCiAgICAgICAgIHBsb3RfYmdjb2xvciA9ICIjZTVlY2Y2IikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCnRlbXAgPC0gZGF0b3NfcGFwZXIgJT4lIA0KICBtdXRhdGUoeV9yYW5nZSA9IGNhc2Vfd2hlbih5ZWFyIDwgMjAwNyB+ICcyMDAyIC0gMjAwNicsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPCAyMDEyIH4gJzIwMDcgLSAyMDExJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA8IDIwMTcgfiAnMjAxMiAtIDIwMTYnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gJzIwMTcgLSAyMDIyJykpICU+JQ0KICBmaWx0ZXIoIXllYXIgPCAgMjAwMiwgIXllYXIgPiAyMDIyLCAhY291bnRyeSAlaW4lIGMoJ1NTJykpICU+JQ0KICBtZXJnZShteV9jb3VudHJpZXMsIGJ5LnggPSAiY291bnRyeSIsIGJ5LnkgPSAiaXNvMmMiKSAlPiUNCiAgbWVyZ2UoY291bnRyeV9jbGFzcykgJT4lDQogIGdyb3VwX2J5KFJlZ2lvbiwgeV9yYW5nZSkgJT4lDQogIHN1bW1hcmlzZShzdW09c3VtKE9EQS5BTEwpLCAuZ3JvdXBzID0gImRyb3AiKSANCg0KdGVtcCAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHlfcmFuZ2UsIHZhbHVlc19mcm9tID0gc3VtKQ0KDQpwbG90X2x5KHRlbXAgJT4lIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBSZWdpb24sIHZhbHVlc19mcm9tID0gc3VtKSwgDQogICAgICAgIHggPSB+eV9yYW5nZSwgeSA9IH5gU3ViLVNhaGFyYW4gQWZyaWNhYCwgbmFtZSA9ICdTdWItU2FoYXJhbiBBZnJpY2EnLCB0eXBlID0gJ2JhcicpICU+JSANCiAgYWRkX3RyYWNlKHkgPSB+YEVhc3QgQXNpYSAmIFBhY2lmaWNgLCBuYW1lID0gJ0Vhc3QgQXNpYSAmIFBhY2lmaWMnKSAlPiUgDQogIGFkZF90cmFjZSh5ID0gfmBNaWRkbGUgRWFzdCAmIE5vcnRoIEFmcmljYWAsIG5hbWUgPSAnTWlkZGxlIEVhc3QgJiBOb3J0aCBBZnJpY2EnKSAlPiUgDQogIGFkZF90cmFjZSh5ID0gfmBTb3V0aCBBc2lhYCwgbmFtZSA9ICdTb3V0aCBBc2lhJykgJT4lIA0KICBhZGRfdHJhY2UoeSA9IH5gTGF0aW4gQW1lcmljYSAmIENhcmliYmVhbmAsIG5hbWUgPSAnTGF0aW4gQW1lcmljYSAmIENhcmliYmVhbicpICU+JSANCiAgYWRkX3RyYWNlKHkgPSB+YEV1cm9wZSAmIENlbnRyYWwgQXNpYWAsIG5hbWUgPSAnRXVyb3BlICYgQ2VudHJhbCBBc2lhJykgJT4lIA0KICBsYXlvdXQodGl0bGUgPSAnQXNpc3RlbmNpYSBPZmljaWFsIHBhcmEgZWwgRGVzYXJyb2xsbyByZWNpYmlkYSB0b3RhbCcsDQogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRG9sYXJlcyBBY3R1YWxlcycpLCB4YXhpcyA9IGxpc3QodGl0bGUgPSAnUGVyaW9kbycpLCBiYXJtb2RlID0gJ2dyb3VwJykNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCnRlbXAgPC0gZGF0b3NfcGFwZXIgJT4lIA0KICBmaWx0ZXIoIXllYXIgPCAgMjAwMiwgIXllYXIgPiAyMDIyLCAhY291bnRyeSAlaW4lIGMoJ1NTJywgJ0tQJykpICU+JQ0KICBtZXJnZShteV9jb3VudHJpZXMsIGJ5LnggPSAiY291bnRyeSIsIGJ5LnkgPSAiaXNvMmMiKSAlPiUNCiAgbWVyZ2UoY291bnRyeV9jbGFzcykNCg0Kc3VwcHJlc3NXYXJuaW5ncygNCiAgcGxvdF9seSh0ZW1wICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwMiwgMjAxMiwgMjAyMikpLCB4ID0gfnllYXIsIHkgPSB+aGRpLCBjb2xvciA9IH5gSW5jb21lIGdyb3VwYCwgdHlwZSA9ICJib3giKSAlPiUNCiAgICBsYXlvdXQodGl0bGUgPSAnSW5kaWNlIGRlIGRlc2Fycm9sbG8gSHVtYW5vIGVuIHBhaXNlcyBkZSBJbmdyZXNvcyBCYWpvcyBlIEluZ3Jlc29zIE1lZGlvcy1iYWpvcycsIA0KICAgICAgICAgICBib3htb2RlID0gImdyb3VwIikNCikNCg0Kc3VwcHJlc3NXYXJuaW5ncygNCiAgcGxvdF9seSh0ZW1wICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwMiwgMjAxMiwgMjAyMikpLCB4ID0gfnllYXIsIHkgPSB+aGRpLCBjb2xvciA9IH5SZWdpb24sIHR5cGUgPSAiYm94IikgJT4lDQogICAgbGF5b3V0KHRpdGxlID0gJ0luZGljZSBkZSBkZXNhcnJvbGxvIEh1bWFubyBzZWd1biBSZWdpb24nLCBib3htb2RlID0gImdyb3VwIikNCikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCnN1cHByZXNzV2FybmluZ3MoDQogIHBsb3RfbHkodGVtcCAlPiUgZmlsdGVyKHllYXIgJWluJSBjKDIwMDIsIDIwMTIsIDIwMjIpKSwgeCA9IH55ZWFyLCB5ID0gfkdPViwgY29sb3IgPSB+YEluY29tZSBncm91cGAsIHR5cGUgPSAiYm94IikgJT4lDQogICAgbGF5b3V0KHRpdGxlID0gJ0luZGljZSBkZSBnb2Jlcm5hbnphIGVuIHBhaXNlcyBkZSBJbmdyZXNvcyBCYWpvcyBlIEluZ3Jlc29zIE1lZGlvcy1iYWpvcycsIGJveG1vZGUgPSAiZ3JvdXAiKQ0KKQ0KDQpzdXBwcmVzc1dhcm5pbmdzKA0KICBwbG90X2x5KHRlbXAgJT4lIGZpbHRlcih5ZWFyICVpbiUgYygyMDAyLCAyMDEyLCAyMDIyKSksIHggPSB+eWVhciwgeSA9IH5HT1YsIGNvbG9yID0gflJlZ2lvbiwgdHlwZSA9ICJib3giKSAlPiUNCiAgICBsYXlvdXQodGl0bGUgPSAnSW5kaWNlIGRlIGdvYmVybmFuemEgc2VndW4gUmVnaW9uJywgYm94bW9kZSA9ICJncm91cCIpDQopDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQpzdXBwcmVzc1dhcm5pbmdzKA0KICBwbG90X2x5KHRlbXAgJT4lIGZpbHRlcih5ZWFyICVpbiUgYygyMDAyLCAyMDEyLCAyMDIyKSksIHggPSB+eWVhciwgeSA9IH5HRFAuUEMsIGNvbG9yID0gfmBJbmNvbWUgZ3JvdXBgLCB0eXBlID0gImJveCIpICU+JQ0KICAgIGxheW91dCh0aXRsZSA9ICdQSUIgcGVyIGNhcGl0YSBlbiBwYWlzZXMgZGUgSW5ncmVzb3MgQmFqb3MgZSBJbmdyZXNvcyBNZWRpb3MtYmFqb3MnLCBib3htb2RlID0gImdyb3VwIikNCikNCg0Kc3VwcHJlc3NXYXJuaW5ncygNCiAgcGxvdF9seSh0ZW1wICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwMiwgMjAxMiwgMjAyMikpLCB4ID0gfnllYXIsIHkgPSB+R0RQLlBDLCBjb2xvciA9IH5SZWdpb24sIHR5cGUgPSAiYm94IikgJT4lDQogICAgbGF5b3V0KHRpdGxlID0gJ1BJQiBwZXIgY2FwaXRhIHNlZ3VuIFJlZ2lvbicsIGJveG1vZGUgPSAiZ3JvdXAiKQ0KKQ0KYGBgDQoNCg0KIyMgTW9kZWxvcyB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyBGaWx0cm9zIHBhcmEgbW9kZWxvDQoNCmBgYHtyfQ0KIyB2YXJpYWJsZXMgZGUgZXRpcXVldGENCnZlIDwtIGMoJ2NvdW50cnknLCAneWVhcicpDQojIHZhcmlhYmxlcyBkZXBuZGllbnRlcw0KdmQgPC0gYygnaGRpJykgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAjICdoZGknLCAnaGRpX2RpZmYnLCAnR0RQLlBDJywgJ0dEUC5QQ19kaWZmJywgJ1BPVicsICdQT1ZfZGlmZicsDQoNCiMgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzDQp2aSA8LSBjKCdPREEuUEMnKSANCiAgICAgICAgICAgICAgICMgJ09EQS5QQycsICdPREEuQUxMJywgJ09EQS5BTExfZGlmZicsICdPREEuUENfZGlmZicsICAgICAgIA0KICAgICAgICAgICAgICAgIyAnT0RBLkFMTF9MT0cnDQoNCiMgdmFyaWFibGVzIGRlIGNvbnRyb2wNCnZjIDwtIGMoJ0dPVicsICdHRFAuUEMnKSANCiAgICAgICAgICAgICAgICMgICdHUk9XJywgJ0NDLkVTVCcsICdHRS5FU1QnLCAnUFYuRVNUJywgJ1JRLkVTVCcsICdSTC5FU1QnLCAnVkEuRVNUJywgJ0dPVicsICdHT1ZfZGlmZicNCiAgICAgICAgICAgICAgICMgICdHRFAuUEMnLCAnUE9MLkNJVi5MSUInLCAnT0RBLlBDXzInLCAnT0RBLkFMTF8yJywgJ09EQS5BTExfTE9HXzInDQoNCiMgdmFyaWFibGVzIGludGVyYWN0aXZhcw0KdmludCA8LSBjKCdHT1ZfR09PRCcpICAgICMgJ0dPVl9HT09EJywgJ1BPTC5DSVYuTElCX0dPT0QnDQoNCiMgcGFpc2VzIHNpbiBkYXRvcw0KZGVsZXRlX2MgPC0gYygnU1MnLCAnQlQnLCAnRVInLCAnR1cnLCAnS1AnLCAnTEInLCAnTkcnLCAnUFMnLCAnU08nLCAnVlUnLCAnRk0nLCAnS0knLCAnU0InLCAnU1knKQ0KICAgICAgICAgICMsCSdNUicsCSdTRCcsCSdXUycgU2kgc2UgdXNhIFBPTC5DSVYuTElCDQogICAgICAgICAgIywgJ0FGJywgJ0NEJywgJ0NJJywgJ0RKJywgJ0tIJywgJ0xSJywgJ01SJywgJ1BHJywgJ1NUJywgJ1RKJywgJ1RMJywgJ1VaJywgJ1ZOJywgJ1dTJywgJ1pXJyBTaSBzZSB1c2EgUE9WDQogICAgICAgICAgIywgJ0xLJywgJ1BIJyBTaSBzZSB1c2EgT0RBLkFMTF9MT0cNCg0KIyBhw7FvcyBzaW4gZGF0b3MNCmZpcnN0X3kgPC0gMjAwMg0KbGFzdF95IDwtIDIwMjIgIyAyMDE4IHNpIHNlIHVzYSBQT1YNCg0KZiA8LSBwYXN0ZSh2ZCwgJ34nLCBjYXNlX3doZW4obGVuZ3RoKHZpbnQpID4gMCB+IHBhc3RlKHZpLCB2aW50LCBzZXAgPSAnKicpLCBUUlVFIH4gdmkpLCAnKycsIHBhc3RlKHZjLCBjb2xsYXBzZSA9ICcgKyAnKSkNCg0KZGF0b3NfbW9kZWwgPC0gZGF0b3NfcGFwZXIgJT4lIA0KICBmaWx0ZXIoIWNvdW50cnkgJWluJSBkZWxldGVfYywgIXllYXIgPCAgZmlyc3RfeSwgIXllYXIgPiBsYXN0X3kpICU+JQ0KICBzZWxlY3QoYWxsX29mKGModmUsIHZkLCB2aSwgdmMsIHZpbnQpKSkNCg0KZGF0b3NfbW9kZWwNCnZpc19kYXQoZGF0b3NfbW9kZWwpDQpgYGANCg0KIyMjIFJlbGFjaW9uZXMNCg0KU2UgcmV2aXNhcmEgbGFzIHJlbGFjaW9uZXMgZW50cmUgbGFzIHZhcmlhYmxlcyBncmFmaWNhbWVudGUgDQoNCmBgYHtyfQ0KbXlfcGxvdCA9IGxpc3QoKQ0KDQpmb3IgKHZkXyBpbiB2ZCkgew0KICBmb3IgKHZpXyBpbiBjKHZpLCB2Yykpew0KICAgIGZpdCA8LSBsbShwYXN0ZSh2ZF8sICd+JywgdmlfKSAsZGF0YSA9IGRhdG9zX21vZGVsKQ0KICAgIG15X3Bsb3RbW3Bhc3RlKHZkXyx2aV8pXV0gPC0gcGxvdF9seSh4ID0gZGF0b3NfbW9kZWxbW3ZpX11dLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRhdG9zX21vZGVsW1t2ZF9dXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlID0gJ21hcmtlcnMnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9IHZpXykgJT4lDQogICAgICBhZGRfbGluZXMoeCA9IGRhdG9zX21vZGVsW1t2aV9dXSwgZml0dGVkKGZpdCksIG5hbWUgPSBwYXN0ZSgidHJhY2UiLCB2aV8pKQ0KICB9DQp9DQoNCnN1YnBsb3QobXlfcGxvdCwgbnJvd3MgPSAyLCBtYXJnaW4gPSAwLjA1KSAgJT4lIGxheW91dCh0aXRsZSA9IHZkKQ0KDQpgYGANCg0KIyMjIENvcnJlciBtb2RlbG9zDQpgYGB7cn0NCm1vZGVsX29scyA8LSBsbShmLCBkYXRhPWRhdG9zX21vZGVsKQ0KbW9kZWxfZmUgPC0gcGxtKGYsIGRhdGE9ZGF0b3NfbW9kZWwsIGluZGV4ID0gdmUsIG1vZGVsID0gIndpdGhpbiIpDQptb2RlbF9yZSA8LSBwbG0oZiwgZGF0YT1kYXRvc19tb2RlbCwgaW5kZXggPSB2ZSwgbW9kZWwgPSAicmFuZG9tIikNCmBgYA0KDQoNCiMjIyBNb2RlbG8gT0xTDQoNCmBgYHtyfQ0KcHJpbnQoZikNCnN1bW1hcnkobW9kZWxfb2xzKQ0KcmVzaWR1YWxQbG90cyhtb2RlbF9vbHMpDQpwbG90KG1vZGVsX29scykNCnZpZihtb2RlbF9vbHMpDQpgYGANCg0KIyMjIE1vZGVsbyBGaXhlZCBFZmZlY3RzDQoNCmBgYHtyfQ0KcHJpbnQoZikNCnN1bW1hcnkobW9kZWxfZmUpDQojc3VtbWFyeShsbShwYXN0ZShmLCAnKyBjb3VudHJ5JyksIGRhdGE9ZGF0b3NfbW9kZWwpKQ0KYGBgDQoNCiMjIyBNb2RlbG8gUmFuZG9tIEVmZmVjdHMNCg0KYGBge3J9DQpwcmludChmKQ0Kc3VtbWFyeShtb2RlbF9yZSkNCmBgYA0KDQojIyMgSGF1c21hbiBUZXN0DQoNCmBgYHtyfQ0KcHJpbnQoZikNCnBodGVzdChtb2RlbF9mZSwgbW9kZWxfcmUpDQpgYGANCiMjIyBVbml0IFJvb3QgVGVzdA0KYGBge3J9DQpkZj11ci5kZihkYXRvc19tb2RlbCAgJT4lIGZpbHRlcihjb3VudHJ5ID09ICdBTycpICU+JSAuW1t2aV1dLHR5cGU9Im5vbmUiLGxhZ3M9MCkNCmRmDQpwcmludCgnTGEgc2VyaWUgZXMgZXN0YWNpb25hcmlhIHNpIGVsIHZhbG9yIGRlbCBlc3RhZGlzdGljbyBkZSBwcnVlYmEgZXhjZWRlIGVzdG9zIHZhbG9yZXMgYWwgOTklLCA5NSUgeSA5MCUgcmVzcGVjdGl2YW1lbnRlJykNCnFub3JtKGMoLjAxLC4wNSwuMSkvMikNCg0KYWRmLnRlc3QoZGF0b3NfbW9kZWxbW3ZpXV0sIGs9IDApDQoNCnkgPC0gZGF0YS5mcmFtZShzcGxpdChkYXRvc19tb2RlbFtbdmldXSwgZGF0b3NfbW9kZWwkY291bnRyeSkpICMgaW5kaXZpZHVhbHMgaW4gY29sdW1ucw0KDQpwdXJ0ZXN0KHksIHBtYXggPSA0LCBleG8gPSAiaW50ZXJjZXB0IiwgdGVzdCA9ICJtYWR3dSIpDQpgYGANCiMjIyBDcm9zcy1TZWN0aW9uYWwgRGVwZW5kYW5jZQ0KYGBge3J9DQpwY2R0ZXN0KG1vZGVsX2ZlLCB0ZXN0ID0gYygibG0iKSkNCnBjZHRlc3QobW9kZWxfZmUsIHRlc3QgPSBjKCJjZCIpKQ0KYGBgDQojIyMgU2VyaWFsIENvcnJlbGF0aW9uDQpgYGB7cn0NCnBiZ3Rlc3QobW9kZWxfZmUpDQpgYGANCiMjIyBIb21vc2tlZGFzdGljaXR5DQpgYGB7cn0NCiNicHRlc3QoaGRpIH4gT0RBLlBDKkdPVl9HT09EICsgR0RQLlBDICsgR09WLCBkYXRhID0gZGF0b3NfbW9kZWwsIHN0dWRlbnRpemUgPSBGKQ0KcHJpbnQoJ2FsdGVybmF0aXZlIGh5cG90aGVzaXM6IEhldGVyb3NjZWRhc3RpY2lkYWQnKQ0KYGBgDQoNCiMjIyBDb250cm9sbGluZyBIZXRlcm9za2VkYXN0aWNpdHkNCmBgYHtyfQ0KY29lZnRlc3QobW9kZWxfZmUpDQoNCmNvZWZ0ZXN0KG1vZGVsX2ZlLCB2Y292SEMobW9kZWxfZmUsIHR5cGUgPSAiSEMzIikpDQpgYGANCg0KDQojIyBHdWFyZGFyIERhdGENCmBgYHtyfQ0KI3NhdmUoZiwgZGVsZXRlX2MsIGZpcnN0X3ksIGxhc3RfeSwgbXlfcGxvdCwgbW9kZWxfb2xzLCBtb2RlbF9mZSwgbW9kZWxfcmUsIGZpbGUgPSAiaGRpX09EQS5QQ0dPVl9HT09EX0dPVl9HRFAuUENfUE9MLkNJVi5MSUIuUkRhdGEiKQ0KYGBgDQoNCg0KIyMgQ2FyZ2FyIERhdGENCmBgYHtyfQ0KI2xvYWQoImhkaV9PREEuUENHT1ZfR09PRF9HT1ZfR0RQLlBDX0dST1cuUkRhdGEiKQ0KI2xvYWQoImhkaV9PREEuUENHT1ZfR09PRF9HT1ZfR0RQLlBDX1BPTC5DSVYuTElCLlJEYXRhIikNCiNsb2FkKCJoZGlfT0RBLlBDR09WX0dPT0RfR09WX0dEUC5QQy5SRGF0YSIpDQojbG9hZCgiR0RQLlBDX09EQS5QQ0dPVl9HT09EX0dPVl9HUk9XLlJEYXRhIikNCiNsb2FkKCJQT1ZfT0RBLlBDR09WX0dPT0RfR09WX0dEUC5QQ19HUk9XLlJEYXRhIikNCmxvYWQoIkdPVl9PREEuUENfaGRpX0dEUC5QQy5SRGF0YSIpDQpgYGANCg0KDQpgYGB7cn0NCndyaXRlX3hsc3goY291bnRyeV9jbGFzcyAlPiUgc2VsZWN0KENvZGUsIFJlZ2lvbiwgYEluY29tZSBncm91cGApICU+JSBmaWx0ZXIoIWlzLm5hKFJlZ2lvbiksICFpcy5uYShgSW5jb21lIGdyb3VwYCkpICU+JQ0KICBtZXJnZShXRElfZGF0YSRjb3VudHJ5LCBieS54PSdDb2RlJywgYnkueSA9J2lzbzNjJykgJT4lIHNlbGVjdChDb2RlLCBpc28yYywgY291bnRyeSwgUmVnaW9uLCBgSW5jb21lIGdyb3VwYCksICdncm91cCBpbmNvbWUueGxzJykNCmBgYA0KDQo=